/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.transas.zorlog.data.log;

import com.transas.zorlog.data.DataSource;
import com.transas.zorlog.data.DataSourcePacketized;
import java.io.*;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 *
 * @author amalikov
 */
public class PacketLogLoader implements LogLoader {
	public enum PacketType {FCS, GCS, BINS}

	public PacketLogLoader(String logFileName, String cfgFileName, PacketType packetType) {
		this.logFileName = logFileName;
		this.cfgFileName = cfgFileName;
		this.packetType = packetType;
		packetMap = new TreeMap<>();
	}
	
	@Override
	public DataSource read(ProgressInformer informer) throws FileNotFoundException, IOException {
		ds = new DataSourcePacketized();
		readCfg();
		readLog(informer);
		return ds;
	}
	
	private void readCfg() throws FileNotFoundException, IOException {
		try (Reader file = new FileReader(cfgFileName)) {
			cfg = new Config(file);
			cfg.read();
		}
	}
	
	private void readLog(ProgressInformer informer) throws FileNotFoundException, IOException {
		try (InputStream file = new BufferedInputStream(new FileInputStream(logFileName))) {
			log = createPacketReader(file);
			while (doOnePacket())
				informer.set(log.getProgress());
			ds.setTimeSource(cfg.createTimeSource(ds, version));
		}
	}
	
	private PacketReader createPacketReader(InputStream in) throws IOException {
		switch (packetType) {
		case FCS: return new FcsPacketReader(in);
		case GCS: return new GcsPacketReader(in);
		case BINS: return new BinsPacketReader(in);
		default:
			throw new IOException();
		}
	}

	private boolean doOnePacket() throws IOException {
		ByteBuffer packet = log.getPacket();
		
		if (packet == null)
			return false;
		
		final int id = log.getId(packet);
		
		if (id == 0)
			version = packet.get(3) & 0xFF;
		else {
			PacketParser parser = cfg.getParserMap(version).get(id);

			if (parser != null) {
				packetMap.put(id, packet);
				if (parser.isMaster())
					addRow();
			}
		}

		return true;
	}

	private void addRow() {
		List<PacketAdapter> row = new ArrayList<>();
		
		for (Map.Entry<Integer, PacketParser> entry : cfg.getParserMap(version).entrySet()) {
			final PacketParser parser = entry.getValue();
			final ByteBuffer buf = packetMap.get(entry.getKey());
			row.add(new PacketAdapter(parser, buf));
		}
		
		ds.addRow(row);
	}

	private String logFileName;
	private String cfgFileName;	
	private PacketType packetType;
	private DataSourcePacketized ds;
	private Config cfg;
	private Map<Integer, ByteBuffer> packetMap;	
	private PacketReader log;
	private int version = 1;
}
